#pragma once
#include <queue>
#include "Mutex.hpp"
#include "Pthread.hpp"
#include "cond.hpp"
#include "Log.hpp"

using namespace CondModule;
using namespace MutexModule;
using namespace ThreadModlue;
using namespace LogModule;

/*----------- 线程池 ----------*/

namespace PthreadPoolModule
{
    static const int gunm = 5;
    template <class T>
    class PthreadPool
    {
    public:
        // 构造的同时通过 lambda 传this指针调用任务处理函数
        PthreadPool(int num = gunm) : ThreadNum(num), _running(false), _SleepPthreadNum(0)
        {
            for (int i = 0; i < ThreadNum; i++)
            {
                _threads.emplace_back(
                    // lambda表达式捕获列表传 this 表示以值捕获当前类对象的指针  这意味着lambda 内部调用 类的 函数 HandlerTask()
                    /// 参数列表 ()： 这里 lambda 表达式的参数列表为空，表示这个可调用对象在调用时不需要传入额外的参数。
                    [this]()
                    {
                        HandlerTask();
                    });
            }
        }

        // 线程池起动
        // 将线程池初始化时存储到vector的线程通过范围for 遍历创建
        void Start()
        {
            // 注意这里一定要传引用
            // 如果不传引用，会开辟一个新的空间，那么Start开启的并不是_threads的线程。
            if (_running)
                return;
            _running = true;

            for (auto &thread : _threads)
            {
                thread.Start();
            }
        }

        // 唤醒所以线程
        void WakeupAllpthread()
        {
            _cond.Broadcast();
        }
        // 唤醒单个线程
        void WakeupOnePthread()
        {
            _cond.Signal();
        }

        void Stop()
        {
            
            if (!_running)
                return;
            
            _running = false;   
            WakeupAllpthread();
        }

        void Join()
        {
            for (auto thread : _threads)
            {
                thread.Join();
                LOG(LogLevel::DEBUG) << "Join一个线程:";
            }
        }

        bool Equeue(const T &in)
        {
            if (_running)
            {
                LockGuard lockguard(_mutex);
                _Taskq.push(in);
                // 休眠线程等于创建的线程
                if (_SleepPthreadNum == ThreadNum)
                {
                    WakeupOnePthread();
                }
                return true;
            }
            return false;
        }

        // 任务处理函数
        void HandlerTask()
        {
            char name[128];
            pthread_getname_np(pthread_self(), name, sizeof(name));
            LOG(LogLevel::DEBUG) << "创建一个线程:" << name;
            while (true)
            {
                T t;
                {
                    LockGuard lockguard(_mutex);
                    // 任务列表为空
                    if (_Taskq.empty() && _running)
                    {
                        _SleepPthreadNum++;
                        _cond.Wait(_mutex);
                        _SleepPthreadNum--;
                    }
                    // 运行标志位为false 并且任务列表没有任务
                    if (_running == false && _Taskq.empty())
                    {
                        ThreadNum--;
                        LOG(LogLevel::DEBUG) << "一个线程退出";
                        break;
                    }
                    // 任务列表不为空
                    LOG(LogLevel::DEBUG) << "任务不为空";
                    t = _Taskq.front(); // 从任务列表拿第一个任务
                    _Taskq.pop();       // 删除任务列表第一个任务
                }
                t();
            }
        }

    private:
        std::vector<Thread> _threads; // 顺序表存储线程
        int ThreadNum;                // 线程个数

        std::queue<T> _Taskq; // 任务列表
        Mutex _mutex;
        Cond _cond;

        bool _running;        // 线程池是否启动
        int _SleepPthreadNum; // 休眠线程
    };
}